﻿
#include "EGraphics.h"
#include "EWindow.h"
#include "EMeshUtil.h"
#include "EUtil.h"
#include "EGame.h"
#include "../res/resource.h"
#include "EMesh.h"

using namespace Base3D;
/*
 * import core
 * import engine
 * new SceneManager
 * render
 * gl
 *
 */
class Game:public EGame{

};

#include "test.hpp"
//#include "glm
//#include "H:\init\git_oschina\libs\glfw-3.1.1\include\GLFW/glfw3.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
//#include "glf"
//#include "H:\in"
#include "gli.hpp"
#include "windows.h"

namespace
{
    /*
     * #version 330 core

#define FRAG_COLOR	0

precision highp float;
precision highp int;
layout(std140, column_major) uniform;

uniform sampler2DRect Diffuse;

in block
{
	vec2 Texcoord;
} In;

layout(location = FRAG_COLOR, index = 0) out vec4 Color;

void main()
{
	Color = texture(Diffuse, In.Texcoord);
}

     */
    /*
     * #version 330 core

#define POSITION	0
#define TEXCOORD	4

precision highp float;
precision highp int;
layout(std140, column_major) uniform;

uniform mat4 MVP;

layout(location = POSITION) in vec2 Position;
layout(location = TEXCOORD) in vec2 Texcoord;

out block
{
	vec2 Texcoord;
} Out;

void main()
{
	Out.Texcoord = Texcoord;
	gl_Position = MVP * vec4(Position, 0.0, 1.0);
}

     */
    char const* VERT_SHADER_SOURCE("gl-330/texture-rect.vert");
    char const* FRAG_SHADER_SOURCE("gl-330/texture-rect.frag");
    char const* TEXTURE_DIFFUSE("kueken7_rgba8_srgb.dds");

    struct vertex
    {
        vertex
                (
                        glm::vec2 const & Position,
                        glm::vec2 const & TexCoord
                ) :
                Position(Position),
                TexCoord(TexCoord)
        {}

        glm::vec2 Position;
        glm::vec2 TexCoord;
    };

    GLsizei const VertexCount = 6;
    GLsizeiptr const VertexSize = VertexCount * sizeof(vertex);
    vertex const VertexData[VertexCount] =
            {
                    vertex(glm::vec2(-1.0f,-1.0f), glm::vec2(-128.0f, 384.0f)),
                    vertex(glm::vec2( 1.0f,-1.0f), glm::vec2( 384.0f, 384.0f)),
                    vertex(glm::vec2( 1.0f, 1.0f), glm::vec2( 384.0f,-128.0f)),
                    vertex(glm::vec2( 1.0f, 1.0f), glm::vec2( 384.0f,-128.0f)),
                    vertex(glm::vec2(-1.0f, 1.0f), glm::vec2(-128.0f,-128.0f)),
                    vertex(glm::vec2(-1.0f,-1.0f), glm::vec2(-128.0f, 384.0f))
            };

    GLuint VertexArrayName = 0;
    GLuint ProgramName = 0;
    GLuint BufferName = 0;
    GLuint TextureRectName = 0;
    GLint UniformMVP = 0;
    GLint UniformDiffuse = 0;
}//namespace

//SDL2main.lib(SDL_windows_main.obj) : error LNK2005: _main 已经在 WinMain.cpp.obj 中定义
//LINK : warning LNK4217:符号“___glewActiveTexture”(在“ framework.lib(glew.obj)”中定义)已由“WinMain.cpp.obj”(函数“"private: bool __thiscall sample::initTexture(void)" (?initTexture@sample@@AAE_NXZ)”中)导入
class sample : public framework
{
public:
    sample(int argc, char* argv[], std::string _meshName ) :
            framework(argc, argv, "gl-330-texture-rect", framework::CORE, 3, 3), meshName( _meshName )
    {
        mesh = nullptr;
    }

private:
    std::string meshName;
    EMesh *mesh;
    //?
    bool initProgram()
    {
        bool Validated = true;

        if(Validated)
        {
            compiler Compiler;
            GLuint VertShaderName = Compiler.create(GL_VERTEX_SHADER,
                                                    getDataDirectory() + VERT_SHADER_SOURCE, "--version 330 --profile core");
            GLuint FragShaderName = Compiler.create(GL_FRAGMENT_SHADER,
                                                    getDataDirectory() + FRAG_SHADER_SOURCE, "--version 330 --profile core");
            Validated = Validated && Compiler.check();

            ProgramName = glCreateProgram();
            glAttachShader(ProgramName, VertShaderName);
            glAttachShader(ProgramName, FragShaderName);
            glLinkProgram(ProgramName);
            Validated = Validated && Compiler.check_program(ProgramName);
        }

        if(Validated)
        {
            //?
            UniformMVP = glGetUniformLocation(ProgramName, "MVP");
            UniformDiffuse = glGetUniformLocation(ProgramName, "Diffuse");
        }

        return Validated;
    }

    /*
     * index
     */
    bool initBuffer()
    {
        //type: software|gl
        std::string name = "Tank1_Body";
        std::string meshName = "Tank1_Body.mesh";
        mesh = new EMesh(name, meshName);
    //buffer
        //mesh->getSubMeshNumber();
        if( mesh ){
            EObject4D* object4D = mesh->getObject();
            glGenBuffers(1, &BufferName);

            glBindBuffer(GL_ARRAY_BUFFER, BufferName);
            //
            glBufferData(GL_ARRAY_BUFFER, VertexSize, VertexData, GL_STATIC_DRAW);
            glBindBuffer(GL_ARRAY_BUFFER, 0);

            return true;
        }
        return false;
    }

    bool initTexture()
    {
        glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

        GLint TextureSize = 0;
        glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE, &TextureSize);

        glGenTextures(1, &TextureRectName);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_RECTANGLE, TextureRectName);
        glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_BASE_LEVEL, 0);
        glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAX_LEVEL, 0);
        glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        gli::texture2d Texture(gli::load_dds((getDataDirectory() + TEXTURE_DIFFUSE).c_str()));
        gli::gl GL(gli::gl::PROFILE_GL33);
        gli::gl::format const Format = GL.translate(Texture.format(), Texture.swizzles());

        assert(
                Texture.extent().x <= std::size_t(TextureSize) &&
                Texture.extent().y <= std::size_t(TextureSize));
        //
        glTexImage2D(GL_TEXTURE_RECTANGLE, static_cast<GLint>(0),
                     Format.Internal,
                     static_cast<GLsizei>(Texture.extent().x), static_cast<GLsizei>(Texture.extent().y),
                     0,
                     Format.External, Format.Type,
                     Texture.data());

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        return true;
    }

    /*
     * gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
        gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
     */
    bool initVertexArray()
    {
        //
        glGenVertexArrays(1, &VertexArrayName);
        glBindVertexArray(VertexArrayName);
        glBindBuffer(GL_ARRAY_BUFFER, BufferName);
        //drawScene
        glVertexAttribPointer(semantic::attr::POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), BUFFER_OFFSET(0));
        glVertexAttribPointer(semantic::attr::TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), BUFFER_OFFSET(sizeof(glm::vec2)));
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glEnableVertexAttribArray(semantic::attr::POSITION);
        glEnableVertexAttribArray(semantic::attr::TEXCOORD);
        glBindVertexArray(0);

        return true;
    }

    bool begin()
    {
        bool Validated = true;

        if(Validated)
            Validated = initProgram();
        if(Validated)
            Validated = initBuffer();
        if(Validated)
            Validated = initVertexArray();
        if(Validated)
            Validated = initTexture();

        return Validated;
    }

    bool end()
    {
        glDeleteBuffers(1, &BufferName);
        glDeleteProgram(ProgramName);
        glDeleteTextures(1, &TextureRectName);
        glDeleteVertexArrays(1, &VertexArrayName);
        if( mesh )
            delete mesh;
        return true;
    }

    /*
     * webGl render
     *
     *         gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
     *         mvMatrix;
     *         mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);
     * gl.bindBuffer(gl.ARRAY_BUFFER, laptopVertexPositionBuffer);
            gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, laptopVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

            gl.bindBuffer(gl.ARRAY_BUFFER, laptopVertexTextureCoordBuffer);
            gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, laptopVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);

            gl.bindBuffer(gl.ARRAY_BUFFER, laptopVertexNormalBuffer);
            gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, laptopVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0);

            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, laptopVertexIndexBuffer);
            setMatrixUniforms();
            gl.drawElements(gl.TRIANGLES, laptopVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
     */
    bool render()
    {
        glm::ivec2 WindowSize(this->getWindowSize());

        //define a matrix
        //glm::mat4 Projection = glm::perspective(glm::pi<float>() * 0.25f, 4.0f / 3.0f, 0.1f, 100.0f);
        glm::mat4 Projection = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f);
        glm::mat4 Model = glm::mat4(1.0f);
        glm::mat4 MVP = Projection * glm::mat4(1.0f) * Model;
        //?
        glViewport(0, 0, WindowSize.x, WindowSize.y);
        //
        glClearBufferfv(GL_COLOR, 0, &glm::vec4(0.0f)[0]);

        // Bind the program for use
        glUseProgram(ProgramName);
        //
        glUniform1i(UniformDiffuse, 0);
        //push to shader: pMatrix
        glUniformMatrix4fv(UniformMVP, 1, GL_FALSE, &MVP[0][0]);

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_RECTANGLE, TextureRectName);
        //??
        //gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
        //gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
        glBindVertexArray(VertexArrayName);
        //gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);
        //with index: gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
        //        mvPopMatrix();
        glDrawArraysInstanced(GL_TRIANGLES, 0, VertexCount, 1);
        //glDrawElementsInstanced
        //glDrawElementsInstancedBaseVertexBaseInstance
        return true;
    }
};

/**
 * redesign:
 *  WndProc:
 *      inputListener
 * EGame:
 *  keyPress
 * Game::Update
 *
 */
 /*
  * wxWidget
  */
int WINAPI WinMain(
				   HINSTANCE hInstance,      // handle to current instance
				   HINSTANCE hPrevInstance,  // handle to previous instance
				   LPSTR lpCmdLine,          // command line
				   int nCmdShow              // show state
				   )
{

    //MessageBoxA( 0, lpCmdLine, "ABC", MB_OK );
    LPSTR path = lpCmdLine;
    WIN32_FIND_DATA data;
    HANDLE h = FindFirstFile(path, &data);
    int retVal = 0;
    if (h != INVALID_HANDLE_VALUE) {
        int Error = 0;

        int argc = 1;
        char* argv[] = {"glew"};
        sample Sample( argc, argv, lpCmdLine );
        Error += Sample();

        return Error;
        CloseHandle(h);
    }
    else {
        //MessageBox(0, "文件不存在", "文件不存在", MB_OK | MB_ICONERROR );
        MessageBox(0, path, "文件不存在", MB_OK | MB_ICONERROR);
        return -1;
    }
    return retVal;
	return 0;
}

